package com.atm.thirdplt.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.atm.thirdplt.common.constant.Constants;
import com.atm.thirdplt.common.core.domain.AjaxResult;
import com.atm.thirdplt.common.core.domain.ca.CaPatInfo;
import com.atm.thirdplt.common.core.domain.ca.CaUploadPdfParm;
import com.atm.thirdplt.common.core.domain.his.AtmHisConfig;
import com.atm.thirdplt.common.core.domain.his.AtmHisMaterial;
import com.atm.thirdplt.common.core.domain.his.TestPriceList;
import com.atm.thirdplt.common.core.domain.his.TestWriteHis;
import com.atm.thirdplt.common.utils.StringUtils;
import com.atm.thirdplt.common.utils.ca.CaSignUtil;
import com.atm.thirdplt.dao.mapper.ca.AtmCaMapper;
import com.atm.thirdplt.dao.mapper.his.AtmHisConfigMapper;
import com.atm.thirdplt.dao.mapper.his.AtmHisMaterialMapper;
import com.atm.thirdplt.dao.mapper.his.TestPriceListMapper;
import com.atm.thirdplt.dao.mapper.his.TestWriteHisMapper;
import com.atm.thirdplt.service.AtmCaService;
import com.atm.thirdplt.service.AtmHisConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.http.protocol.HTTP;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.prefs.BackingStoreException;
import java.util.stream.Collectors;

/**
 * CA自动签名 服务实现类
 *
 * @author：l
 * @date：2023/02/17
 */
@Slf4j
@Service("/atmCaServiceImpl")
public class AtmCaServiceImpl implements AtmCaService {

    @Value("${ca.appId}")
    private String appId;

    @Value("${ca.url}")
    private String url;

    @Value("${ca.key}")
    private String key;

    @Value("${ca.webUrl}")
    private String webUrl;

    @Autowired
    private AtmCaMapper caMapper;


    /**
     * 获取签名图片
     *
     * @return
     */
    @Transactional

    @Override
    public AjaxResult queryCaUserImg(String caUserId) {
        Map<String,String> parmMap = new HashMap<>();

        parmMap.put("version", Constants.CA_PARM_VERSION);
        parmMap.put("appId",appId);
        parmMap.put("signAlgo", Constants.CA_PARM_SIGNALGO);
        parmMap.put("userId", caUserId);

        //log.info("获取签名图片parm:[{}]", JSON.toJSONString(parmMap));

        try {
            //转化请求参数
            String parm = CaSignUtil.generateRequestJson(parmMap, key);
            //log.info("获取签名图片parm转换后:[{}]", JSON.toJSONString(parmMap));
            //调用CA自动签名接口
            Map<String, Object> resrtMap = sedHttpPost(url + Constants.CA_URL_QUERY_IMAGE, parm);

            //log.info("获取签名图片调用后:[{}]", JSON.toJSONString(resrtMap));

            if(!"200".equals(String.valueOf(resrtMap.get("status")))){
                return AjaxResult.error(String.valueOf(resrtMap.get("message")));
            };

            Map<String,String> dataMap = JSON.parseObject(String.valueOf(resrtMap.get("data")), Map.class);

            if(CollUtil.isEmpty(dataMap) || StringUtils.isEmpty(dataMap.get("image"))){

                return AjaxResult.error("调用CA获取签名图片接口返回CA用户签名图片为空!");
            }

            //修改用户签名图片
            caMapper.updateCaUserImg(caUserId,dataMap.get("image"));

            return AjaxResult.success();

        }catch (Exception e){
            log.error("调用CA获取签名图片签错误：" + e);
            return AjaxResult.error("调用CA获取签名图片接口报错");
            //throw new BackingStoreException("调用CA添加签名任务接口报错");
        }

    }

    /**
     * 添加签名任务-扫码类型
     *
     * @param parmMap 参数
     * @return
     */
    @Transactional
    @Override
    public AjaxResult addCaSign(Map<String,String> parmMap){
        if (CollUtil.isEmpty(parmMap)) {
            return AjaxResult.success();
        }
        Map<String,String> reqMap = new HashMap<>();
        reqMap.put("version", Constants.CA_PARM_VERSION);
        reqMap.put("appId",appId);
        reqMap.put("signAlgo", Constants.CA_PARM_SIGNALGO);
        reqMap.put("dataType", Constants.CA_PARM_DATATYPE);
        reqMap.put("algo", Constants.CA_PARM_ALGO);
        reqMap.put("title", parmMap.get("title"));
        reqMap.put("description", parmMap.get("description"));
        reqMap.put("data", CaSignUtil.base64Encode(parmMap.get("data").getBytes()));

        //log.info("添加签名任务parm:[{}]", JSON.toJSONString(reqMap));

        try {
            //转化请求参数
            String parm = CaSignUtil.generateRequestJson(reqMap, key);
            //log.info("添加签名任务parm转换后:[{}]", JSON.toJSONString(reqMap));
            //调用CA自动签名接口
            Map<String, Object> resrtMap = sedHttpPost(url + Constants.CA_URL_SIGN_JOB, parm);

            //log.info("添加签名任务调用后:[{}]", JSON.toJSONString(resrtMap));

            if(!"200".equals(String.valueOf(resrtMap.get("status")))){
                return AjaxResult.error(String.valueOf(resrtMap.get("message")));
            };

            return AjaxResult.success(resrtMap.get("data"));

        }catch (Exception e){
           log.error("调用CA添加签名任务错误：" + e);
           return AjaxResult.error("调用CA添加签名任务接口报错");
            //throw new BackingStoreException("调用CA添加签名任务接口报错");
        }
    }

    /**
     * 开启自动签-扫码
     *
     * @return
     */
    @Override
    public AjaxResult startAutoSign() {

        Map<String,String> parmMap = new HashMap<>();

        parmMap.put("version", Constants.CA_PARM_VERSION);
        parmMap.put("appId",appId);
        parmMap.put("signAlgo", Constants.CA_PARM_SIGNALGO);
        parmMap.put("timeRegion", "2400");

        //log.info("开启自动签parm:[{}]", JSON.toJSONString(parmMap));

        try {
            //转化请求参数
            String parm = CaSignUtil.generateRequestJson(parmMap, key);
            //log.info("开启自动签parm转换后:[{}]", JSON.toJSONString(parmMap));
            //调用CA自动签名接口
            Map<String, Object> resrtMap = sedHttpPost(url + Constants.CA_URL_START_AUTO_SIGN, parm);

            //log.info("开启自动签调用后:[{}]", JSON.toJSONString(resrtMap));

            if(!"200".equals(String.valueOf(resrtMap.get("status")))){
                return AjaxResult.error(String.valueOf(resrtMap.get("message")));
            };

            return AjaxResult.success(resrtMap.get("data"));

        }catch (Exception e){
            log.error("调用CA开启自动签错误：" + e);
            return AjaxResult.error("调用CA开启自动签接口报错");
            //throw new BackingStoreException("调用CA添加签名任务接口报错");
        }
    }

    /**
     * 获取签名结果
     *
     * @return
     */
    @Override
    public AjaxResult getSignResult(String signDataId) {
        Map<String,String> parmMap = new HashMap<>();

        parmMap.put("version", Constants.CA_PARM_VERSION);
        parmMap.put("appId",appId);
        parmMap.put("signAlgo", Constants.CA_PARM_SIGNALGO);
        parmMap.put("signDataId", signDataId);
        //log.info("获取签名结果parm:[{}]", JSON.toJSONString(parmMap));

        try {
            //转化请求参数
            String parm = CaSignUtil.generateRequestJson(parmMap, key);
            //log.info("获取签名结果parm转换后:[{}]", JSON.toJSONString(parmMap));
            //调用CA自动签名接口
            Map<String, Object> resrtMap = sedHttpPost(url + Constants.CA_URL_GET_SIGN_RESULT, parm);

            //log.info("获取签名结果调用后:[{}]", JSON.toJSONString(resrtMap));

            if(!"200".equals(String.valueOf(resrtMap.get("status")))){
                return AjaxResult.error(String.valueOf(resrtMap.get("message")));
            };

            return AjaxResult.success(resrtMap.get("data"));

        }catch (Exception e){
            log.error("调用CA获取签名结果错误：" + e);
            return AjaxResult.error("调用CA获取签名结果接口报错");
            //throw new BackingStoreException("调用CA添加签名任务接口报错");
        }
    }

    /**
     * 上传PDF
     *
     * @param pdfParm 参数
     * @return
     */
    @Override
    public AjaxResult uploadCaPdf(CaUploadPdfParm pdfParm) {
        //查询本地数据库病人信息
        CaPatInfo patInfo = caMapper.getpatInfo(pdfParm.getPatientId(), pdfParm.getVisitId(), pdfParm.getOperId());
        pdfParm.setPatnum(patInfo.getVisitId());
        pdfParm.setPatname(patInfo.getName());
        pdfParm.setPatsex(patInfo.getSex());
        pdfParm.setBedno(patInfo.getBedNo());

        //组装请求参数
        String parmXml = assembleUploadPdfParm(pdfParm);
        log.info("上传PDF参数: "+ parmXml);
        try {
            //调用上传PDF接口
          String respXml =  HttpRequest.post(webUrl).contentType("application/soap+xml; charset=utf-8").timeout(-1).body(parmXml).execute().body();
            //String  respXml  = HttpUtil.post(webUrl,parmXml);
            respXml = StringUtils.handXml(respXml);
            log.info("上传PDF后: " + respXml);

            Document doc = DocumentHelper.parseText(respXml);
            Element rootEle = doc.getRootElement();
            // 获取返回状态码并处理 0/1（0-失败 1-成功）
            String returnCode = rootEle.element("result").getTextTrim();
            if ("0".equals(returnCode)) {
                return AjaxResult.error( rootEle.element("error").getTextTrim());
            }

            return AjaxResult.success();

        }catch (Exception e){
            log.error("调用上传PDF接口错误: " + e);
            return AjaxResult.error("回传PDF失败");
        }
    }

    /**
     *  撤销PDF
     *
     * @param pdfParmList 参数
     * @return
     */
    @Override
    public AjaxResult removeCaPdf(List<CaUploadPdfParm> pdfParmList) {

        if(CollUtil.isEmpty(pdfParmList)){
            return AjaxResult.success();
        }

        try {
            //返回标志
            boolean success = false;
            //错误信息
            String errMsg = "";
            for (CaUploadPdfParm pdfParm : pdfParmList) {
                //组装请求参数
                String parmXml = assembleRemoveDocParm(pdfParm);
                log.info("撤销PDF参数: "+ parmXml);
                //调用上传PDF接口
                String respXml =  HttpRequest.post(webUrl).contentType("application/soap+xml; charset=utf-8").timeout(-1).body(parmXml).execute().body();
                respXml = StringUtils.handXml(respXml);
                log.info("撤销PDF后: " + respXml);

                Document doc = DocumentHelper.parseText(respXml);
                Element rootEle = doc.getRootElement();
                // 获取返回状态码并处理 0/1（0-失败 1-成功）
                String returnCode = rootEle.element("result").getTextTrim();
                if ("0".equals(returnCode)) {
                    success = true;
                    errMsg = errMsg + rootEle.element("error").getTextTrim();
                }
            }
            if(success){
                return AjaxResult.error(errMsg);
            }

            return AjaxResult.success();

        }catch (Exception e){
            log.error("调用撤销PDF接口错误: " + e);
            return AjaxResult.error("撤销PDF失败");
        }
    }

    /**
     * 组装上传pdf请求参数
     *
     * @param pdfParm
     * @return
     */
    private String assembleUploadPdfParm(CaUploadPdfParm pdfParm){
        StringBuilder strbuil = new StringBuilder();
        String xmlHand = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">\n" +
                "  <soap12:Body>\n" +
                "    <UploadDoc xmlns=\"http://tempuri.org/\">\n" +
                "      <sDocXml>";
        String xmlEnd = "</sDocXml>\n" +
                "    </UploadDoc>\n" +
                "  </soap12:Body>\n" +
                "</soap12:Envelope>";
        strbuil.append(xmlHand).append("<![CDATA[<request><docsource>").append("A501").append("</docsource><pin>").append("2143252B-74B7-7572-C723-53252B5A648C")
                .append("</pin><docid>").append(pdfParm.getDocid()).append("</docid><patientno>").append(pdfParm.getPatientId())
                .append("</patientno><title>").append(pdfParm.getTitle()).append("</title><gestno>").append(pdfParm.getPatientId())
                .append("</gestno><patnum>").append(pdfParm.getPatnum()).append("</patnum><patname>").append(pdfParm.getPatname())
                .append("</patname><patsex>").append(pdfParm.getPatsex()).append("</patsex><bedno>").append("</bedno><author>")
                .append(pdfParm.getAuthor()).append("</author><filetype>PDF</filetype><docdate>").append(DateUtil.format(pdfParm.getDocdate(),"yyyy-MM-dd HH:mm:ss"))
                .append("</docdate><reportdate>").append(DateUtil.now()).append("</reportdate>")
                .append("<doctemplatecode>").append(pdfParm.getDoctemplatecode()).append("</doctemplatecode><doctemplatename>")
                .append(pdfParm.getDoctemplatename()).append("</doctemplatename><seqno>").append(pdfParm.getSeqno()).append("</seqno>")
                .append("<body><text mediatype=\"application/pdf\" encode=\"base64\">")
                .append(CaSignUtil.base64Encode(pdfParm.getBodyText())).append("</text></body></request>]]>").append(xmlEnd);
        return strbuil.toString();
    }

    /**
     * 组装撤销pdf请求参数
     *
     * @param pdfParm
     * @return
     */
    private String assembleRemoveDocParm(CaUploadPdfParm pdfParm){
        StringBuilder strbuil = new StringBuilder();
        String xmlHand = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">\n" +
                "  <soap12:Body>\n" +
                "    <RemoveDoc xmlns=\"http://tempuri.org/\">\n" +
                "      <sDocXml>";
        String xmlEnd = "</sDocXml>\n" +
                "    </RemoveDoc>\n" +
                "  </soap12:Body>\n" +
                "</soap12:Envelope>";
        strbuil.append(xmlHand).append("<![CDATA[<request><docsource>").append("A501").append("</docsource><pin>").append("2143252B-74B7-7572-C723-53252B5A648C")
                .append("</pin><docid>").append(pdfParm.getDocid()).append("</docid><patientno>").append(pdfParm.getPatientId())
                .append("</patientno><gestno>").append(pdfParm.getPatientId()).append("</gestno><docdate>")
                //.append(DateUtil.format(pdfParm.getDocdate(),"yyyy-MM-dd HH:mm:ss"))
                .append(DateUtil.now()).append("</docdate>")
                .append("</request>]]>").append(xmlEnd);
        return strbuil.toString();
    }



    /**
     * 调用CA系统-HTTP-POST请求
     *
     * @param url 请求地址
     *
     * @return  同步结果
     */
    private Map<String,Object> sedHttpPost(String url, String parm){

        String  body  = HttpUtil.post(url,parm);

        return JSON.parseObject(body, Map.class);
    }

}